package coolenv

import (
	"context"
	coolenvpb "coolcar/coolenv/api/gen/v1"
	"coolcar/coolenv/pos"
	"math"
	"time"

	cmap "github.com/orcaman/concurrent-map"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

const (
	ARC = 6371000.0 //6378137.0
	rad = math.Pi / 180.0
)

type service struct {
	carPosChans cmap.ConcurrentMap
	pos.Publisher
	PosSimInterval time.Duration
	Logger         *zap.Logger
	coolenvpb.UnimplementedAIServiceServer
}

func Service(carPosChans cmap.ConcurrentMap, pub pos.Publisher, posSimInterval time.Duration, log *zap.Logger) *service {
	return &service{
		carPosChans:    carPosChans,
		Publisher:      pub,
		PosSimInterval: posSimInterval,
		Logger:         log,
	}
}

// LicIdentity 返回图片识别信息
func (s *service) LicIdentity(ctx context.Context, req *coolenvpb.IdentityRequest) (*coolenvpb.Identity, error) {
	if !req.RealAi {
		return &coolenvpb.Identity{
			LicNumber:       "3119305",
			Name:            "刘烨",
			Gender:          coolenvpb.Gender_MALE,
			BirthDateMillis: 996595200000,
		}, nil
	}
	// 调用ai接口
	return &coolenvpb.Identity{
		LicNumber:       "AI识别出来的驾驶证号",
		Name:            "AI识别出来的姓名",
		Gender:          coolenvpb.Gender_FEMALE,
		BirthDateMillis: 960242766000,
	}, nil
}

// MeasureDistance 计算两地的距离
func (s *service) MeasureDistance(ctx context.Context, req *coolenvpb.MeasureDistanceRequest) (*coolenvpb.MeasureDistanceResponse, error) {
	lat1 := req.From.Latitude * rad
	long1 := req.From.Longitude * rad
	lat2 := req.To.Latitude * rad
	long2 := req.To.Longitude * rad
	theta := long2 - long1
	dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta))
	return &coolenvpb.MeasureDistanceResponse{
		DistanceKm: dist * ARC / 1000,
	}, nil
}

// SimulateCarPos 模拟汽车位置
func (s *service) SimulateCarPos(ctx context.Context, req *coolenvpb.SimulateCarPosRequest) (*coolenvpb.SimulateCarPosResponse, error) {
	c := pos.Controller(s.carPosChans, s.Publisher, s.PosSimInterval, s.Logger)
	c.RunPosSimulations(ctx, &coolenvpb.CarPosUpdate{
		CarId: req.CarId,
		Pos:   req.InitialPos,
	})
	return &coolenvpb.SimulateCarPosResponse{}, nil
}

// EndSimulateCarPos 结束模拟汽车位置
func (s *service) EndSimulateCarPos(ctx context.Context, req *coolenvpb.EndSimulateCarPosRequest) (*coolenvpb.EndSimulateCarPosResponse, error) {
	notFountErr := status.Errorf(codes.NotFound, "")
	tmp, ok := s.carPosChans.Get(req.CarId)
	if !ok {
		return nil, notFountErr
	}
	ch, ok := tmp.(*chan struct{})
	if !ok {
		return nil, notFountErr
	}
	close(*ch)
	s.carPosChans.Remove(req.CarId)
	return &coolenvpb.EndSimulateCarPosResponse{}, nil
}
